Error BoundaryとSuspense
責務が異なる
壊れたUIを表示するのではなく、「エラーが起きました」のような代替UIを表示する
壊れたUIを表示するのではなく、「loading...」のような代替UIを表示する
何が似ているか
Componentを書く際に、errorが起きた時や、fetch中の表示を考えなくて済む
従来はこんな感じに書いていた
code:ts
// プロフィールを表示することが責務であるComponent
const Profile = () => {
const { value, isError, isLoading } = useFetch();
if(isError) {
return (..)
}
if(isLoading) {
return (..)
}
return <div>{value}</div>
}
Error BoundaryやSuspenceを使うことで、errorやloadingを気にする必要がない
code:ts
// プロフィールを表示することが責務であるComponent
const Profile = () => {
const { value } = useFetch();
// この辺でerror処理を書かなくて良い
// この辺でloading時の処理を書かなくて良い
return <div>{value}</div>
}
「プロフィールを表示する」という責務に則ったことだけを書いてれば良い
では、実際にerrorが起きた時や、fetch中にどうするか?
それ専用のComopnentを用意する
error時の処理は、<ErrorBoundary />のようなComponentを作って
「errorが起きた時に何かを表示する」という責務のみを全うする
fetch時も、<Loading />のようなComponentを作って、
「良い感じのloadingを表示する」という責務のみを全うする
これを使いたいまとまりごとにComponentで囲うだけ
code:ts
<ErrorBoundary>
<Suspense fallback={<Loading/>}>
<Profile/>
</Suspense>
</ErrorBoundary>
Profileで待ち時間が生じた場合は<Loading/>が表示され
Profileでerrorが生じた場合は、<ErrorBoundary/>内のerror messageが表示される
<Profile/>のComponentの定義内では、errorやloadingのことを気にしなくていい
より宣言的になった、と言える
囲う粒度は自由で、project全体を1つ囲うだけでも良いし、刻んでも良い
捕捉したいまとまりを囲んで使う
code:ts
<A>
<B/>
<ErrorBoundary1>
<C/>
<ErrorBoundary2>
<D/>
<E/>
</ErrorBoundary2>
<ErrorBoundary3>
<F />
</ErrorBoundary3>
</ErrorBoundary1>
<A/>
この場合、Dでerroが生じた場合は、DとEの両方が、代替物に置き換わる
そうすれば例えばfooterでerrorが起きた時に、contents部分には何も影響がないとか、
YouTubeのような動画サイトを作って表示する時に、
動画部分を1番優先的に表示して、
関連動画とかは後で読み込む
のようなことが簡単に書ける
両者ともView上のtry/catchのようなイメージ
<Profile/>のComponentの中で、errorやloadingが生じたことに対してhandlingしない
親(以上のなにか)がhandlingする
親かもしれないし、親の親かもしれない
直近でhandlingしている親のとこまで飛ぶ
内部でthrowした時に、直近のtryまで吹っ飛んでhandlingされるtry/catchと似ている
Suspenseには
コレは両方とも待ち時間の話をしていて、
「何の待ち時間か」の部分が異なるだけ